<?php

namespace falcon5\inc\Infrastructure\Services;

use Exception;
use falcon5\inc\Base\Common;
use falcon5\inc\Base\ProxyHeader;
use falcon5\inc\Base\WPOption;
use falcon5\inc\Base\WPUrlMode;
use falcon5\inc\Exceptions\InvalidArgumentException;
use falcon5\inc\Helpers\FileCacheHelper;
use falcon5\inc\Helpers\HttpRequestHelper;
use falcon5\inc\Helpers\HttpResponseHelper;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\RequestOptions;
use hollisho\helpers\ArrayHelper;
use hollisho\httpclient\BaseClient;
use lucatume\DI52\ContainerException;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Cache\CacheItem;
use falcon5\inc\Base\EditModeConfig;

class ProxyService
{
    /**
     * 处理翻译请求
     * @param string $path
     * @param string $lang
     * @param string $originalLanguage
     * @param string $protocol
     * @param string $host
     * @throws ContainerException
     * @throws GuzzleException
     */
    public function processTranslation(string $path, string $lang, string $originalLanguage, string $protocol, string $host)
    {
        try {

            $this->getHtmlFromEngine($host, $path, $lang, $originalLanguage, $protocol);
        } catch (Exception $e) {
            falcon5_error_log($e->getMessage());
        }
    }

    /**
     * @param string $path
     * @param string $lang
     * @param string $protocol
     * @return void
     * @throws ContainerException
     */
    public function getHtmlFromCache(string $path, string $lang, string $protocol)
    {
        /** @var WPOption $falcon5Option */
        $falcon5Option = falcon5_app(WPOption::class);
        if (!$falcon5Option->isOpenCacheDir()) {
            return;
        }
        /** @var CacheService $cacheService */
        $cacheService = falcon5_app(CacheService::class);
        $filename = $cacheService->getFilename($path, $lang, $protocol);
        $cacheInfo = $cacheService->getCacheByFilename($filename);
        /** @var CacheItem $item */
        $item =  FileCacheHelper::get($filename);
        if ($item->isHit()) {
            status_header(200);

            if ($cacheInfo) {
                header(ProxyHeader::FC5_CACHE_TIME . ': ' . $cacheInfo->created_at, false);
            }

            echo $item->get();
            exit;
        }
    }

    /**
     * @param string $host
     * @param string $path
     * @param string $lang
     * @param string $originalLanguage
     * @param string $protocol
     * @return void
     * @throws ContainerException
     * @throws GuzzleException
     * @throws InvalidArgumentException|\hollisho\helpers\InvalidArgumentException
     */
    public function getHtmlFromEngine(string $host, string $path, string $lang, string $originalLanguage, string $protocol)
    {

        $headers = $this->prepareRequestHeaders($host, $lang, $path, $originalLanguage, $protocol);
        if (!$this->handleEditMode($headers, $lang)) {
            // 非编辑模式，尝试读取缓存
            // api/engine/can_edit
            // 用户用户权限（）
            //$this->getHtmlFromCache($path, $lang, $protocol);
        }
        $parentPageCache = "";
        /** @var WPOption $falcon5Option */
        $falcon5Option = falcon5_app(WPOption::class);
        $OPT_FC5_TRANS_MASTER_PAGE_CACHE = $falcon5Option->getOption("FC5_TRANS_MASTER_PAGE_CACHE") ?? false;
        if ((defined("FC5_TRANS_MASTER_PAGE_CACHE") && constant("FC5_TRANS_MASTER_PAGE_CACHE") == true) || $OPT_FC5_TRANS_MASTER_PAGE_CACHE) {
            $cacheService = falcon5_app(CacheService::class);
            $filename = $cacheService->getFilename($path, "", "");
            $item =  FileCacheHelper::get($filename) ?? null;

            if ($item && $item->isHit()) {
                $parentPageCache = $item->get();
            }
        }
        $allHeaders = HttpRequestHelper::getAllHeaders($headers);
        $allHeaders["url"] = $allHeaders["fc5-protocol"] . "://" . $host . $path;
        $allHeaders["source-lang"] = strtolower($originalLanguage); //todu
        $allHeaders["fc5_source-lang"] = $allHeaders["source-lang"];
        $allHeaders["fc5-source-lang"] = $allHeaders["source-lang"];
        $allHeaders["target-lang"] = $allHeaders["fc5-target-lang"];

        //$method = $_SERVER['REQUEST_METHOD'];
        $method = "POST";
        try {
            $targetResponse = $this->getTargetHtmlContent($method, $_GET, $_POST, $allHeaders, $parentPageCache);
            $statusCode = $targetResponse->getStatusCode();

            $body = $targetResponse->getBody()->getContents();
            $responseHeaders = $targetResponse->getHeaders();

            // 设置响应状态码
            status_header($statusCode);

            // 处理响应头
            HttpResponseHelper::echoHeaders($responseHeaders, $host, $lang);

            // 根据状态码处理响应
            $this->handleResponseByStatusCode($statusCode, $responseHeaders, $body, $host, $path, $lang, $protocol);
        } catch (Exception $e) {
            $this->logProxyError($e, $host, $path, $lang);
            return;
        }
    }

    /**
     * 准备请求头信息
     * 
     * @param string $host
     * @param string $lang
     * @param string $path
     * @param string $originalLanguage
     * @param string $protocol
     * @return array
     * @throws ContainerException
     */
    private function prepareRequestHeaders(string $host, string $lang, string $path, string $originalLanguage, string $protocol): array
    {
        /** @var WPOption $falcon5Option */
        $falcon5Option = falcon5_app(WPOption::class);
        $apikey = $falcon5Option->getApiKey();

        return [
            ProxyHeader::FC5_CLIENT => Common::getClientType(),
            ProxyHeader::FC5_PATH => $path,
            ProxyHeader::FC5_TARGET_LANG => $lang,
            ProxyHeader::FC5_API_KEY => $apikey,
            ProxyHeader::FC5_PROTOCOL => $protocol,
            ProxyHeader::FC5_HOST => $host,
            ProxyHeader::FC5_PROXY_HOST => $falcon5Option->getUrlMode() == WPUrlMode::URL_MODE_SUBFOLDER ?
                sprintf("%s/%s", $host, $lang) : sprintf("%s.%s", $lang, $host),
            ProxyHeader::FC5_SOURCE_LANG => $originalLanguage,
        ];
    }

    /**
     * 处理编辑模式
     *
     * @param array $headers
     * @param string $lang
     * @return bool
     * @throws ContainerException
     */
    private function handleEditMode(array &$headers, string $lang="")
    {
        
        $canEdit = false;
        /** @var EditModeConfig $editModeConfig */
        //$editModeConfig = falcon5_app(EditModeConfig::class);

        /** @var WPOption $falcon5Option */
        $falcon5Option = falcon5_app(WPOption::class);
        $apikey = $falcon5Option->getApiKey();
        $headers["language-edit"]=0;
        // if ($editModeConfig->validateEditModeParams($_GET)) {


        //     $editModeConfig->clearEditModeParams($_GET);
        // }
        try {
            /** @var Falcon5Service $falcon5Service */
            $falcon5Service = falcon5_app(Falcon5Service::class);
            $params = [
                'api_key' => $apikey,
                'rule' => 'engine/can_edit'
            ];

            $result = $falcon5Service->checkUserLanguageEditPermission($params);
            
            if (ArrayHelper::getValue($result, 'code') != 1) {
                throw new Exception(ArrayHelper::getValue($result, 'msg'), ArrayHelper::getValue($result, 'code'));
            }
            $headers["language-edit"]=1;
            $canEdit = true;
        } catch (Exception $e) {
            falcon5_error_log('Caught exception: ' . $e->getMessage());
        }
        
        $canEdit && $headers[ProxyHeader::FC5_LANGUAGE_EDIT] = 1;
        return $canEdit;
    }

    /**
     * 根据状态码处理响应
     * 
     * @param int $statusCode
     * @param array $responseHeaders
     * @param string $body
     * @param string $host
     * @param string $path
     * @param string $lang
     * @param string $protocol
     * @return void
     * @throws ContainerException|\hollisho\helpers\InvalidArgumentException
     */
    private function handleResponseByStatusCode(int $statusCode, array $responseHeaders, string $body, string $host, string $path, string $lang, string $protocol)
    {
        if ($statusCode === 200) {
            $this->handleSuccessResponse($responseHeaders, $body, $path, $lang, $protocol);
        } elseif ($statusCode === 301 || $statusCode === 302) {
            $this->handleRedirectResponse($responseHeaders, $statusCode, $lang);
        }
        // 其他状态码：返回原始URL的内容
    }

    /**
     * 处理成功响应
     * 
     * @param array $responseHeaders
     * @param string $body
     * @param string $path
     * @param string $lang
     * @param string $protocol
     * @return void
     * @throws ContainerException|\hollisho\helpers\InvalidArgumentException
     */
    private function handleSuccessResponse(array $responseHeaders, string $body, string $path, string $lang, string $protocol)
    {
        $pageId = $responseHeaders["X-Page-Id"][0] ?? "";
        $urlSlug = $responseHeaders["X-Url-Slug"][0] ?? "";
        $proxyError = $responseHeaders["X-Proxy-Error"][0] ?? "";
        $body = HttpResponseHelper::echoHtml($body, $lang);

        //complete translation event
        apply_filters(Common::Fc5_TEANSLATION_COMPLETE_BODY_FILTER_HOOK, []);
        if (!$proxyError && $pageId) {
            //$this->saveResponseToCache($path, $urlSlug, $lang, $protocol, $body, $pageId);
            //$path,$lang,$body
            $ages = ["page" => $path, "lang" => $lang, "body" => $body, "pageId" => $pageId];
            do_action(Common::Fc5_TEANSLATION_COMPLETE_HOOK, $ages);
            $applyResult = apply_filters(Common::Fc5_TEANSLATION_COMPLETE_BODY_FILTER_HOOK, $body) ?? "";
            if ($applyResult) {
                $body = $applyResult;
            }
        } else {
            $ages = ["page" => $path, "lang" => $lang, "error" => $proxyError, "pageId" => $pageId];
            do_action(Common::Fc5_TEANSLATION_FAILURE_HOOK, $ages);
        }
        echo $body;
        exit;
    }

    /**
     * 保存响应到缓存
     * 
     * @param string $path
     * @param string $urlSlug
     * @param string $lang
     * @param string $protocol
     * @param string $body
     * @param int $pageId
     * @return void
     * @throws ContainerException
     */
    private function saveResponseToCache(string $path, string $urlSlug, string $lang, string $protocol, string $body, int $pageId)
    {
        $path = $urlSlug != $path ? $urlSlug : $path;
        /** @var CacheService $cacheService */
        $cacheService = falcon5_app(CacheService::class);
        $filename = $cacheService->getFilename($path, $lang, $protocol);;
        $cacheService->saveCache($path, $lang, $filename, $pageId);
        FileCacheHelper::set($filename, $body);
    }

    /**
     * 处理重定向响应
     *
     * @param array $responseHeaders
     * @param int $statusCode
     * @param string $lang
     * @return void
     * @throws \hollisho\helpers\InvalidArgumentException
     */
    private function handleRedirectResponse(array $responseHeaders, int $statusCode, string $lang)
    {
        $location = ArrayHelper::getValue($responseHeaders, 'Location.0');
        if ($location) {
            // 如果是相对路径，添加语言前缀
            if (strpos($location, '/') === 0) {
                $location = '/' . $lang . $location;
            }
            wp_redirect($location, $statusCode);
            exit;
        }
    }

    /**
     * 记录代理错误
     * 
     * @param Exception $e
     * @param string $host
     * @param string $path
     * @param string $lang
     * @return void
     */
    private function logProxyError(Exception $e, string $host, string $path, string $lang)
    {
        falcon5_log()->error('Proxy error: ' . $e->getMessage(), [
            'host' => $host,
            'path' => $path,
            'lang' => $lang,
            'error' => $e->getMessage()
        ]);
    }

    /**
     * 获取html内容
     * @param $method
     * @param array $query
     * @param array $form_params
     * @param array $headers
     * @return ResponseInterface
     * @throws GuzzleException
     */
    public function getTargetHtmlContent($method, array $query = [], array $form_params = [], array $headers = [], $parentPageCache = ""): ResponseInterface
    {
        $client = new BaseClient(Common::getEngineProxyHost());

        $client->setDefaultOptions([
            RequestOptions::HTTP_ERRORS => false,
            RequestOptions::ALLOW_REDIRECTS => false,
            RequestOptions::VERIFY => false,
            //            'debug' => true,
        ]);

        $options = [
            RequestOptions::QUERY => $query,
            RequestOptions::HEADERS => $headers,
        ];
        if ($parentPageCache) {
            $options[RequestOptions::BODY] = $parentPageCache;
        }
        if (empty($parentPageCache) && isset($headers['Content-Type'])) {
            if (!strpos($headers['Content-Type'], 'application/json')) {
                $options = array_merge($options, [
                    RequestOptions::FORM_PARAMS => $form_params,
                ]);
            } else {
                $options = array_merge($options, [
                    RequestOptions::JSON => $form_params,
                ]);
            }
        }
        $trace = $options["query"]["trace"] ?? $options["headers"]["trace"] ?? "";
        unset($options["query"]["trace"]);
        $targetResponse = $client->request('/site/html', $method, $options);
        if (!empty($trace)) {
            echo "func_get_args:" . PHP_EOL;
            var_dump(func_get_args());
            echo "client:" . PHP_EOL;
            $pageId = ArrayHelper::getValue($targetResponse->getHeaders(), 'X-Page-ID.0') ?? ArrayHelper::getValue($targetResponse->getHeaders(), 'X-Page-Id.0', 0);
            echo "Page ID:";
            var_dump($pageId);
            echo "client:" . PHP_EOL;
            var_dump($client);
            echo "options:" . PHP_EOL;
            var_dump($options);
            echo "response headers:" . PHP_EOL;
            var_dump($targetResponse->getHeaders());
            echo "response html:" . PHP_EOL;
            var_dump($targetResponse->getBody()->getContents());
            exit();
        }
        return $targetResponse;
    }
}
